package com.online.pay.common.sign;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

/**
 * 签名的辅助类，获取各种信息, 实现签名接口
 * 
 * @author Pengdingqi wuhang
 *
 */
public class CertificateCoder {

	public static final String CERT_TYPE = "X.509";
	public static final String CMSZ_CERT_PATH_NAME = "cer.path";
	public static final String MER_CERT_PATH_NAME = "mer.cer.path";
	public static final String CER_FILE_NAME = "test.crt";
	public static final String KEYSTROE_PATH_NAME = "keystore.path";
	public static final String KEYSTROE_PASSWORD_NAME = "keystore.password";
	public static final String KEYSTROE_ALIAS_NAME = "keystore.alias";
	public static final String SIGN_ALGORITHM = "SHA256withRsa";

	public static PrivateKey privateKey;

	public static String privateKeyId;
	
	public static String merPublicKeyId;
	public static String cmszPublicKeyId;

	public static PublicKey merPublicKey;
	public static PublicKey cmszPublicKey;

	private static ThreadLocal<Signature> signature = new ThreadLocal<Signature>() {
		@Override
		protected Signature initialValue() {
			Signature s = null;
			try {
				s = Signature.getInstance(SIGN_ALGORITHM);
			} catch (NoSuchAlgorithmException e) {
				new RuntimeException(e);
			}
			return s;
		}
	};

	static{
		init();
	}
	
	public static void init(){
		ConfUtil.init();
		// 初始化 KeyStore
		loadKeyStore(ConfUtil.get(KEYSTROE_PATH_NAME), ConfUtil.get(KEYSTROE_PASSWORD_NAME),
				ConfUtil.get(KEYSTROE_ALIAS_NAME));
		// 初始化验签 Certificate
		loadCmszCertificate(ConfUtil.get(CMSZ_CERT_PATH_NAME));
		//初始化keystore对应的certificate
		loadMerCertificate(ConfUtil.get(MER_CERT_PATH_NAME));
	}

	/**
	 * 加载KeyStore与私钥
	 */
	static void loadKeyStore(String keyStoreFilePath, String keyStorePassword, String alias) {
		assert !StringUtils.isBlank(keyStoreFilePath);
		assert !StringUtils.isBlank(keyStorePassword);
		assert !StringUtils.isBlank(alias);

		try {
			KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
			FileInputStream in = new FileInputStream(keyStoreFilePath);
			ks.load(in, keyStorePassword.toCharArray());
			privateKey = (PrivateKey) ks.getKey(alias, keyStorePassword.toCharArray());
			X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
			privateKeyId = cert.getSerialNumber().toString(16);
		} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException
				| UnrecoverableKeyException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 加载keystore对应证书公钥
	 */
	static void loadMerCertificate(String certFilePath) {
		X509Certificate cert509 = loadCertificate(certFilePath);
		merPublicKeyId = cert509.getSerialNumber().toString(16);
		merPublicKey = cert509.getPublicKey();
	}
	static void loadCmszCertificate(String certFilePath) {
		X509Certificate cert509 = loadCertificate(certFilePath);
		cmszPublicKeyId = cert509.getSerialNumber().toString(16);
		cmszPublicKey = cert509.getPublicKey();
	}
	
	static X509Certificate loadCertificate(String certFilePath) {
		try {
			CertificateFactory factory = CertificateFactory.getInstance(CERT_TYPE);
			Certificate cert;
			if (StringUtils.isBlank(certFilePath)) {
				InputStream in = SignUtil.class.getResourceAsStream("/" + CER_FILE_NAME);
				cert = factory.generateCertificate(in);
			} else {
				FileInputStream in = new FileInputStream(certFilePath);
				cert = factory.generateCertificate(in);
			}
			X509Certificate cert509 = (X509Certificate)cert;
			return cert509;
		} catch (CertificateException | FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}

	
	/**
	 * 签名
	 * 
	 * @param data
	 *            - 待签名的串
	 * @return 签名结果
	 */
	public static byte[] sign(byte[] data) {
		Signature sa = signature.get();
		byte[] result = null;
		try {
			sa.initSign(privateKey);
			sa.update(data);
			result = sa.sign();
		} catch (InvalidKeyException | SignatureException e) {
			throw new RuntimeException(e);
		}
		return result;
	}

	/**
	 * 验签
	 * 
	 * @param data
	 *            - 待验签的串
	 * @param sign
	 *            - 签名值
	 * @return true验签成功，false验签失败
	 */
	public static boolean verify(byte[] data, byte[] sign) {
		Signature sa = signature.get();
		boolean result = false;
		try {
			sa.initVerify(cmszPublicKey);
			sa.update(data);
			result = sa.verify(sign);
		} catch (InvalidKeyException | SignatureException e) {
			throw new RuntimeException(e);
		}
		return result;
	}

	/**
	 * 获取签名证书ID
	 * 
	 * @return 证书ID
	 */
	public static String getSignCerId() {
		return merPublicKeyId;
	}
}